超详细的Spring Security OAuth2 JWT (SSO)整合项目

您所在的位置:网站首页 oauth20 jwt单点登录 超详细的Spring Security OAuth2 JWT (SSO)整合项目

超详细的Spring Security OAuth2 JWT (SSO)整合项目

2024-02-19 07:09| 来源: 网络整理| 查看: 265

Spring Security OAuth2 JWT SSO 整合项目 前言

本项目为Spring Security OAuth2 JWT SSO整合项目。适合对Spring Security、OAuth2和JWT SSO有一定认识并且想要进行有机整合的各位,项目本着上手最简单,基础功能最完善的原则编写。 基于数据库的认证和鉴权。采用OAuth2认证,根据认证服务器端查询的用户信息,进行认证处理,根据权限在资源服务器进行鉴权。此处采用权限鉴权模式,根据用户的权限,开闸可以访问的资源服务器范围。【另外还有根据角色鉴权,只是换汤不换药】

for (int i = 0; i (2)application.properties server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/auth_test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=123456 mybatis.mapper-locations=classpath:mappers/*.xml 5.利用mybatis-generator生成实体类、Mapper、XML文档。

在这里插入图片描述

6.Security、OAuth2、JWT、SSO配置类 (1)授权服务器

用来进行授权配置。需要继承AuthorizationServerConfigurerAdapter类,重写configure()方法.

AuthorizationServerConfig.java

package com.xxxx.springsecurityoauth2demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; /** * 描述:授权服务器 @EnableAuthorizationServer,extends AuthorizationServerConfigurerAdapter * 为了模拟,授权服务器和资源服务器放在了一起,正常情况是解耦的。 */ @Configuration @EnableAuthorizationServer //开启授权服务器 public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Resource private PasswordEncoder passwordEncoder; @Resource private AuthenticationManager authenticationManager; @Resource private UserDetailsService userDetailsService; @Resource(name = "jwtTokenStore") private TokenStore tokenStore; @Resource(name = "jwtAccessTokenConverter") private JwtAccessTokenConverter jwtAccessTokenConverter; @Resource private JwtTokenEnhancer jwtTokenEnhancer; /** * 密码授权模式的配置 * * @param endpoints * @throws Exception */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { //TokenEnhancerChain是TokenEnhance的一个实现类 TokenEnhancerChain chain = new TokenEnhancerChain(); List delegates = new ArrayList(); delegates.add(jwtTokenEnhancer); delegates.add(jwtAccessTokenConverter);//还要把转换器放进去用来实现jwtTokenEnhancer的互相转换 chain.setTokenEnhancers(delegates); endpoints.authenticationManager(authenticationManager) .userDetailsService(userDetailsService) //可以看到主要是增加了 JwtAccessTokenConverter JWT访问令牌转换器和JwtTokenStore JWT令牌存储组件, //通过AuthorizationServerEndpointsConfigurer 授权服务器端点配置加入两个实例 .tokenStore(tokenStore) .accessTokenConverter(jwtAccessTokenConverter) .tokenEnhancer(chain); //设置JWT增强内容 } /** * 授权配置 * * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { /*传来的参数clients是我们的应用,要去找授权服务器授权,授权完了之后会给我们授权码,我们 * (client)拿着授权码再到授权服务器去获取令牌,获取到令牌之后拿着令牌去资源服务器获取资源 * */ clients.inMemory() //.inMemory()放入内存。我们为了方便,直接放在内存中生成client,正常情况下是我们主动找授权服务器注册的时候才会有处理。 .withClient("client") //指定client。参数为唯一client的id .secret(passwordEncoder.encode("112233")) //指定密钥 .redirectUris("http://www.baidu.com") //指定重定向的地址,通过重定向地址拿到授权码。 //.redirectUris("http://localhost:8081/login") //单点登录到另一服务器 .accessTokenValiditySeconds(60 * 10) //设置Access Token失效时间 .refreshTokenValiditySeconds(60 * 60 * 24) //设置refresh token失效时间 .scopes("all") //指定授权范围 .autoApprove(true) //自动授权,不需要手动允许了 /** * 授权类型: * "authorization_code" 授权码模式 * "password"密码模式 * "refresh_token" 刷新令牌 */ .authorizedGrantTypes("authorization_code", "password", "refresh_token"); //指定授权类型 可以多种授权类型并存。 } /** * 单点登录配置 * * @param security * @throws Exception */ /*@Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { //必须要身份认证,单点登录必须要配置 security.tokenKeyAccess("isAuthenticated()"); } */ } (2)资源管理器

企业生产环境下授权服务器和资源服务器是两个单独的服务器,我们为了学习,使用了单Model项目,所以放在了一起。

ResourceServerConfig.java

package com.xxxx.springsecurityoauth2demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; /** * 描述:资源管理器 @EnableResourceServer,extends ResourceServerConfigurerAdapter * 为了模拟,授权服务器和资源服务器放在了一起,正常情况是解耦的。 */ @Configuration @EnableResourceServer //开启资源服务器 public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.requestMatchers().antMatchers("/api/**").and() .authorizeRequests()//授权的请求 //进行接口的鉴权处理 .antMatchers("/api/user/save").hasAuthority("admin") //其余接口不做鉴权,只需要认证即可 .anyRequest() .authenticated(); } } (3)JWT内容增强器

JwtTokenEnhancer.java

package com.xxxx.springsecurityoauth2demo.config; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import java.util.HashMap; import java.util.Map; /** * 描述:配置JwtTokenEnhancer添加自定义信息 ,继承TokenEnhancer实现一个JWT内容增强器 */ public class JwtTokenEnhancer implements TokenEnhancer { /** * JWT内容增强器 * @param oAuth2AccessToken * @param oAuth2Authentication * @return */ @Override public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) { Map info = new HashMap(); info.put("enhance", "增强的信息"); //给的参数是oAuth2的AccessToken,实现类是DefaultOAuth2AccessToken, //里面有个setAdditionalInformation方法添加自定义信息(Map类型) ((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(info); return oAuth2AccessToken; } } (4)TokenStore配置类

JwtTokenStoreConfig.java

package com.xxxx.springsecurityoauth2demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; /** * 描述:TokenStore配置类。 * TokenStore的实现类,有InMemoryTokenStore、JdbcTokenStore、JwtTokenStore、RedisTokenStore。 * JwtAccessTokenConverter JWT访问令牌转换器和 JwtTokenStore JWT令牌存储组件 */ @Configuration public class JwtTokenStoreConfig { /** * 生成TokenStore来保存token 此处为JwtTokenStore实现 * @return TokenStore */ @Bean public TokenStore jwtTokenStore() { //需要传入JwtAccessTokenConverter return new JwtTokenStore(jwtAccessTokenConverter()); } /** * 生成JwtAccessTokenConverter转换器,并设置密钥 * @return JwtAccessTokenConverter */ @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter(); //设置jwt密钥 jwtAccessTokenConverter.setSigningKey("test_key"); return jwtAccessTokenConverter; } /** * JwtTokenEnhancer的注入 * @return */ @Bean public JwtTokenEnhancer jwtTokenEnhancer() { return new JwtTokenEnhancer(); } } (5)Security核心配置类

SecurityConfig.java

package com.xxxx.springsecurityoauth2demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import javax.annotation.Resource; /** * 描述:Security核心配置类 * 1.重写configure(HttpSecurity http) * 2.配置 PasswordEncoder的Ioc注入。 */ @Configuration @EnableWebSecurity //开启Web Security public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //配置没有权限访问跳转自定义页面 http.exceptionHandling().accessDeniedPage("/unauth.html"); http.authorizeRequests() //放行授权服务器的几个端点请求、登录请求、登出请求。 .antMatchers("/oauth/**", "/login/**", "/logout/**") .permitAll() .anyRequest() .authenticated() //.and() 就相当于回到 http再继续配置 .and() //放行所有的表单请求 .formLogin() .permitAll() .and() //关闭csrf .csrf().disable(); } /** * 密码授权模式用到的AuthenticationManager类 * * @return * @throws Exception */ @Override @Bean protected AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } 7.配置Spring Security的UserDetailService实现从数据库查询信息进行认证 (1)MyUserService接口 package com.xxxx.springsecurityoauth2demo.service; /** * 描述:MyUserService接口 */ public interface MyUserService{ } (2)MyUserServiceImpl package com.xxxx.springsecurityoauth2demo.service.impl; import com.xxxx.springsecurityoauth2demo.model.pojo.SecurityUser; import com.xxxx.springsecurityoauth2demo.model.pojo.User; import com.xxxx.springsecurityoauth2demo.service.MyUserService; import com.xxxx.springsecurityoauth2demo.service.UserService; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * 描述:自定义UserDetailsService实现类 * 名言:越难找的bug往往是越低级的 */ @Service //因为没有加Service注解,所以please login 一直报用户名密码错误!!! public class MyUserServiceImpl implements UserDetailsService, MyUserService { @Resource private PasswordEncoder passwordEncoder; @Resource private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.getUserByUserName(username); String name = user.getName(); String password = user.getPassword(); String authority = user.getAccount(); return new SecurityUser(name, password, AuthorityUtils.commaSeparatedStringToAuthorityList(authority)); } } (3)自定义Security框架的User实体

SecurityUser.java

package com.xxxx.springsecurityoauth2demo.model.pojo; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.Collection; import java.util.List; /** * 描述:自定义Security框架的User实体 */ public class SecurityUser implements UserDetails { private String username; private String password; private List authorities; public SecurityUser(String username, String password, List authorities) { this.username = username; this.password = password; this.authorities = authorities; } @Override public Collection


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3